﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;

namespace eXamineBusiness.SystemDescription.Data
{
    public class GenericCollection<T> : IEnumerable<T>
        where T : DescriptionItem
    {
        private readonly List<T> _list;

        public GenericCollection()
        {
            this._list = new List<T>();
        }
        [ContractInvariantMethod]
        private void ThisCanHaveAnyNameYouWant()
        {
            Contract.Invariant(this._list != null);
            Contract.Invariant(this._list.Count >= 0);
        }

        [Pure]
        public int Count
        {
            get { return _list.Count; }
        }

        public void Add(T thrownEvent)
        {
            Contract.Requires<ArgumentNullException>(thrownEvent != null);
            Contract.Ensures(Contains(thrownEvent));
            if (thrownEvent == null) throw new ArgumentNullException();
            this._list.Add(thrownEvent);
        }

        public void Remove(T thrownEvent)
        {
            Contract.Requires(thrownEvent != null);
            Contract.Ensures(!Contains(thrownEvent));
            this._list.Remove(thrownEvent);
            thrownEvent.SignalAsRemoved();
        }

        public void Remove(String name)
        {
            Contract.Requires(name != null);
            Contract.Requires(Contains(name));
            Contract.Ensures(!Contains(name));
            int i = this._list.FindIndex(e => e.Name.Equals(name));
            this._list[i].SignalAsRemoved();
            this._list.RemoveAt(i);
        }

        public T this[int index]
        {
            get
            {
                Contract.Requires(index < this.Count);
                Contract.Requires(index >= 0);
                return this._list[index];
            }
        }


        public T this[String name]
        {
            get
            {
                Contract.Requires(Contains(name));
                return this._list[this._list.FindIndex(e => e.Name.Equals(name))];
            }
        }

        [Pure]
        public bool Empty
        {
            get
            {
                return this._list.Count == 0;
            }
        }

        public void Clear()
        {
            Contract.Ensures(this.Count == 0);
            List<T> copy = new List<T>(this._list);
            foreach (T description in copy)
            {
                this.Remove(description);
            }
        }

        public IEnumerator<T> GetEnumerator()
        {
            return _list.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        [Pure]
        public bool Contains(string elem)
        {
            if (elem == null) return false;
            foreach (T receivedEventItem in _list)
            {
                if (receivedEventItem.Name.Equals(elem))
                    return true;
            }
            return false;
        }

        [Pure]
        public bool Contains(T receivedEvent)
        {
            if (receivedEvent == null) return false;
            foreach (T receivedEventItem in _list)
            {
                if (receivedEvent.HasParent && receivedEventItem.DeepEquals(receivedEvent))
                    return true;
                else if (!receivedEvent.HasParent && receivedEvent.Equals(receivedEventItem))
                    return true;
            }
            return false;
        }
    }
}
